package cn._2dland.uploader.fiftysix;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;

import cn._2dland.uploader.CountingMultipartRequestEntity;
import cn._2dland.uploader.HttpException;
import cn._2dland.uploader.UploadClient;
import cn._2dland.uploader.UploadHandler;
import cn._2dland.uploader.UploadTask;
import cn._2dland.uploader.utils.HttpUtils;
import cn._2dland.uploader.utils.Logger;
import cn._2dland.uploader.utils.EncodeUtils;

public class FiftySixClient extends UploadClient {
	/** 登录地址 */
	private static final String LOGIN_URL = "http://space.56.com/php/urs.php";
	/** 上传页面地址 */
	private static final String UPLOAD_PAGE = "http://w.56.com/my/index.php?action=Upload";
	/** 提交信息地址 */
	private static final String SUBMIT_URL = "http://w.56.com/my/index.php?action=Upload&do=uploadSubmit";
	/** 默认服务器编号 */
	private static final String DEFAULT_HOST = "138";
	/** token前缀 */
	private static final String TOKEN_PREFIX = "ubkl(tf*72&";

	public FiftySixClient(String user, String pass) {
		super(user, pass);
	}

	public boolean login() {
		try {
			Logger.writec("登录帐号: " + username + " ...");
			PostMethod loginPost = new PostMethod(LOGIN_URL);

			loginPost.addParameter("RemenberMe", "on");
			loginPost.addParameter("autoLogin", "true");
			loginPost.addParameter("ourl", "http://www.56.com/js/login/login_box_success.html");
			loginPost.addParameter("errurl", "http://www.56.com/js/login/login_box_error.html");
			loginPost.addParameter("username", username);
			loginPost.addParameter("password", password);

			int respCode = client.executeMethod(loginPost);
			if(respCode == HttpStatus.SC_MOVED_TEMPORARILY) {
				String location = loginPost.getResponseHeader("Location").getValue();
				bLogin = "http://www.56.com/js/login/login_box_success.html".equals(location);
			}
			loginPost.releaseConnection();

			Logger.writec(bLogin ? "登录成功！" : "登录失败...");
		}
		catch (Exception e) {
			Logger.writec("登录时发生异常，请查看错误日志文件...");
			Logger.error(e);
		}
		return bLogin;
	}

	public boolean upload(UploadTask task) {
		boolean result = false;
		try {
			// 获取flashvars
			Logger.writec("获取上传参数...");
			Map<String, String> vars = getFlashVars();
			String host = vars.get("h");
			Logger.debug("host=v" + host);

			// 获取当前时间
			long time = (long)Math.floor(System.currentTimeMillis() / 1000);
			String token = getToken(time, host);
			Logger.debug("token=" + token);

			// 构造上传URL
			StringBuffer buf = new StringBuffer();
			buf.append("http://v").append(host).append(".56.com/upload")
				.append("?table=").append(getTable()).append("&param_str=").append(vars.get("param_str"))
				.append("&sessid=").append(getSessionID()).append("&user_hex").append(vars.get("user_hex"))
				.append("&t=").append(time).append("&token=").append(token)
				.append("&fileName=").append(URLEncoder.encode(task.fileName, "utf-8"))
				.append("&ng=1&56");

			// 上传视频文件
			Logger.writec("开始上传文件：" + task.fileName);
			PostMethod uploadPost = new PostMethod(buf.toString());
			Part[] parts = {
					new StringPart("Filename", task.fileName),
					new FilePart("Filedata", task.file),
					new StringPart("Upload", "Submit Query")
			};
			RequestEntity reqEntity = new CountingMultipartRequestEntity(parts, 
					uploadPost.getParams(), task.file.length(), new UploadHandler());
			uploadPost.setRequestEntity(reqEntity);
			// 执行上传请求
			int respCode = client.executeMethod(uploadPost);
			if(respCode != HttpStatus.SC_OK)
				throw new HttpException(respCode);
			// 获取上传结果
			String body = HttpUtils.readResponseStream(uploadPost);
			uploadPost.releaseConnection();
			String flvid = pickFLVID(body);

			Logger.writec("文件上传完成，开始提交信息...");
			// 提交视频信息
			PostMethod submitPost = new PostMethod(SUBMIT_URL);
			submitPost.addRequestHeader("Referer", "http://w.56.com/my/index.php?action=Upload");
			submitPost.addParameters(new NameValuePair[]{
				new NameValuePair("Subject", task.title),
				new NameValuePair("Content", task.descript),
				new NameValuePair("tag0", getTag(task.tags, 0)),
				new NameValuePair("tag1", getTag(task.tags, 1)),
				new NameValuePair("tag2", getTag(task.tags, 2)),
				new NameValuePair("tag3", getTag(task.tags, 3)),
				new NameValuePair("tag4", getTag(task.tags, 4)),
				new NameValuePair("channel", task.category),
				new NameValuePair("public", "y"),
				new NameValuePair("author", task.source),
				new NameValuePair("flvid", flvid),
			});
			respCode = client.executeMethod(submitPost);
			if(respCode != HttpStatus.SC_OK)
				throw new HttpException(respCode);

			body = HttpUtils.readResponseStream(submitPost);
			submitPost.releaseConnection();
			result = body.indexOf("成功提交") >= 0;

			if(result) {
				Logger.writec("视频上传成功！");
				Logger.writecf(task.fileName + " -> FlvID=" + flvid);
			} else {
				Logger.writec("视频上传失败...");
				Logger.debug(body);
			}
		} catch (Exception e) {
			Logger.writec("上传时发生异常，请查看错误日志文件...");
			Logger.error(e);
		}
		return result;
	}

	/**
	 * 获取flash参数
	 * @return
	 */
	private Map<String, String> getFlashVars() {
		Map<String, String> vars = new HashMap<String, String>();
		try {
			// 读取页面内容
			GetMethod pageGet = new GetMethod(UPLOAD_PAGE);
			int respCode = client.executeMethod(pageGet);
			if(respCode != HttpStatus.SC_OK)
				throw new Exception("HTTP Error: " + respCode);

			// 获取响应结果
			String body = HttpUtils.readResponseStream(pageGet);
			pageGet.releaseConnection();

			// 查找flashvars
			Matcher m = Pattern.compile("upload.flashVars = '[\\w&=%]+'").matcher(body);
			if(m.find()) {
				String flashVars = body.substring(m.start() + 20, m.end() - 1);
				vars = string2map(flashVars);
			}
			// 容错处理
			if(vars.get("h") == null) vars.put("h", DEFAULT_HOST);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return vars;
	}

	/**
	 * 解析传给Flash的参数串，以Map形式返回
	 * @param str 参数串
	 * @return
	 * @throws Exception
	 */
	private Map<String, String> string2map(String str) throws Exception {
		Map<String, String> map = new HashMap<String, String>();
		String[] vars = str.split("&");
		for(String var : vars) {
			int pos = var.indexOf('=');

			if(pos < 0) {
				// 没有值的情况
				map.put(var, null);
			} else {
				// 拆分出名称和值，需要处理一次URL解码
				String name = var.substring(0, pos);
				String value = var.substring(pos + 1);
				value = URLDecoder.decode(value, "utf-8");
				map.put(name, value);
			}
		}
		return map;
	}

	/**
	 * 构造上传所需的table参数
	 * @return
	 */
	private String getTable() {
		long time = System.currentTimeMillis();
		StringBuffer buf = new StringBuffer();
		buf.append(time).append("year").append(time);
		String table = EncodeUtils.hexMD5(buf.toString().getBytes()).toLowerCase();
		return table;
	}

	/**
	 * 构造上传所需的sessid参数
	 * @return
	 */
	private String getSessionID() {
		String time = String.valueOf(System.currentTimeMillis());
		String sessionID = EncodeUtils.hexMD5(time.getBytes()).toLowerCase();
		return sessionID;
	}

	/**
	 * 构造上传所需的token参数
	 * @param time
	 * @param host
	 * @return
	 */
	private String getToken(long time, String host) {
		StringBuffer buf = new StringBuffer();
		buf.append(TOKEN_PREFIX).append(time).append(host);
		String token = EncodeUtils.hexMD5(buf.toString().getBytes()).toLowerCase();
		return token;
	}

	/**
	 * 从相应信息中获取flvid
	 * @param response
	 * @return
	 */
	private String pickFLVID(String response) {
		String flvid = null;
		Matcher m = Pattern.compile("&id=\\d+&").matcher(response);
		if(m.find())
			flvid = response.substring(m.start() + 4, m.end() - 1);
		
		return flvid;
	}

	/**
	 * 获取tag
	 * @param tags 标签组
	 * @param index 索引
	 * @return
	 */
	private String getTag(String tags, int index) {
		if(tags == null)
			return "";

		String[] arr = tags.split(" ");
		if(index < arr.length)
			return arr[index];
		else
			return "";
	}
}
